package com.goodcol.plugin.tool;

import com.goodcol.plugin.entity.TypeMapper;
import com.goodcol.plugin.entity.TypeMapperGroup;
import com.goodcol.plugin.enums.MatchType;
import com.goodcol.plugin.service.SettingsStorageService;
import com.goodcol.plugin.ui.TypeMapperAddDialog;
import com.intellij.database.model.DasColumn;
import com.intellij.database.psi.DbTable;
import com.intellij.database.util.DasUtil;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.ui.Messages;
import com.intellij.util.containers.JBIterable;

import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.regex.Pattern;
import java.util.regex.PatternSyntaxException;
import java.util.stream.Collectors;

/**
 * 数据库jdbcType和Java类型对应处理工具类
 *
 * @author Shanhy
 * @version 1.0.0
 */
public final class TypeMapperUtils {

    /**
     * 不允许创建实例对象
     */
    private TypeMapperUtils() {
        throw new UnsupportedOperationException();
    }

    /**
     * 参照方法 {@link TypeMapperUtils#processTypeValidator(Project, DbTable)}
     * 区别：该方法为集合
     *
     * @param project     project
     * @param dbTableList 原始表对象集合
     * @return 返回结果表示是否完全处理完毕，如果中途终止则返回false
     */
    public static boolean processTypeValidator(Project project, List<DbTable> dbTableList) {
        for (DbTable dbTable : dbTableList) {
            if (!processTypeValidator(project, dbTable)) {
                return false;
            }
        }
        return true;
    }

    /**
     * 类型校验，如果存在未知类型则引导用于去条件类型
     * 注意：所有缺失的类型都必须存在于Default中，缺失添加的也会添加到Default中，非Default组可以覆盖同名的Default中的映射关系
     *
     * @param project project
     * @param dbTable 原始表对象
     * @return 返回结果表示是否完全处理完毕，如果中途终止则返回false
     */
    public static boolean processTypeValidator(Project project, DbTable dbTable) {
        // 处理所有列
        JBIterable<? extends DasColumn> columns = DasUtil.getColumns(dbTable);
        List<TypeMapper> typeMapperList = SettingGroupUtils.getDefaultTypeMapperGroup().getElementList();

        // 记录对应类型的报错弹窗，避免重复类型重复弹框
        Set<String> typeErrorSet = new HashSet<>();

        for (DasColumn column : columns) {
            String typeName = column.getDasType().getSpecification();
            boolean typeValidFlag = false;
            for (TypeMapper typeMapper : typeMapperList) {
                try {
                    typeValidFlag = checkTypeName(typeMapper, typeName);
                    if(typeValidFlag) {
                        break;
                    }
                } catch (PatternSyntaxException e) {
                    if (!typeErrorSet.contains(typeMapper.getColumnType())) {
                        Messages.showWarningDialog(
                                "类型映射《" + typeMapper.getColumnType() + "》存在语法错误，请及时修正。报错信息:" + e.getMessage(),
                                Constants.TITLE_INFO);
                        typeErrorSet.add(typeMapper.getColumnType());
                    }
                }
            }
            // 如果校验通过，则外层循环直接continue，不弹框Dialog
            if (typeValidFlag) {
                continue;
            }
            // 没找到类型，提示用户选择输入类型
            if (!new TypeMapperAddDialog(project, typeName).showAndGet()) {
                return false;
            }
        }
        return true;
    }

    /**
     * 校验typeName
     *
     * @param typeMapper typeMapper
     * @param typeName   typeName
     * @return data
     */
    public static boolean checkTypeName(TypeMapper typeMapper, String typeName) {
        if (typeMapper.getMatchType() == MatchType.ORDINARY) {
            return typeName.equalsIgnoreCase(typeMapper.getColumnType());
        } else if (typeMapper.getMatchType() == MatchType.REGEX) {
            // 不区分大小写的正则匹配模式
            return Pattern.compile(typeMapper.getColumnType(), Pattern.CASE_INSENSITIVE).matcher(typeName).matches();
        }
        return false;
    }

    /**
     * getJavaType
     *
     * @param dbType    dbType
     * @param groupName groupName
     * @return String
     */
    public static String getJavaType(String dbType, String groupName) {
        TypeMapperGroup targetGroupTypeMapperGroup = SettingsStorageService.getSettingsStorage().getTypeMapperGroupMap().get(groupName);
        for (TypeMapper typeMapper : getMergeDefaultTypeMapperList(targetGroupTypeMapperGroup)) {
            if (typeMapper.getMatchType() == MatchType.ORDINARY) {
                if (dbType.equalsIgnoreCase(typeMapper.getColumnType())) {
                    return typeMapper.getJavaType();
                }
            } else {
                // 不区分大小写的正则匹配模式
                if (Pattern.compile(typeMapper.getColumnType(), Pattern.CASE_INSENSITIVE).matcher(dbType).matches()) {
                    return typeMapper.getJavaType();
                }
            }
        }
        return "java.lang.Object";
    }

    /**
     * 返回目标group和Default组合并后的TypeMapper集合
     *
     * @param targetGroupTypeMapperGroup targetGroupTypeMapperGroup
     * @return TypeMapper集合
     */
    public static List<TypeMapper> getMergeDefaultTypeMapperList(TypeMapperGroup targetGroupTypeMapperGroup) {
        TypeMapperGroup defaultTypeMapperGroup = SettingsStorageService.getSettingsStorage()
                .getTypeMapperGroupMap().get("Default");
        if (targetGroupTypeMapperGroup == null) {
            return defaultTypeMapperGroup.getElementList();
        }
        List<TypeMapper> targetGroupTypeMapperList = targetGroupTypeMapperGroup.getElementList();
        Map<String, TypeMapper> typeMapperGroupMap = targetGroupTypeMapperList.stream()
                .collect(Collectors.toMap(typeMapper -> typeMapper.getMatchType().toString().concat(":")
                        .concat(typeMapper.getColumnType()), typeMapper -> typeMapper));
        // 从Default组中过滤出所有不存在于目标group中的配置
        List<TypeMapper> notExistsTargetGroupList = defaultTypeMapperGroup.getElementList().stream()
                .filter(typeMapper -> !typeMapperGroupMap.containsKey(typeMapper.getMatchType().toString().concat(":")
                        .concat(typeMapper.getColumnType()))).collect(Collectors.toList());
        // 最后将Default组中所有不存在于目标group中的TypeMapper都添加到结果中返回
        List<TypeMapper> resultList = new ArrayList<>();
        resultList.addAll(targetGroupTypeMapperList);
        resultList.addAll(notExistsTargetGroupList);
        return resultList;
    }

}
